﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using Shoozla.DataModel.Helper;
using System.Diagnostics;

namespace Shoozla.DataModel
{
    /// <summary>
    /// Scan a folder and read all the Mp3 file 
    /// </summary>
    public class FileSaver : IProgressOperation
    {
        //interface implementation
        public int Minimum { get; set; }
        public int Maximum { get; set; }
        public int Current { get; set; }
        public String Description { get; set; }

        public event EventHandler<ProgressOperationEventArgs> ProgressChanged;
        public event EventHandler<ProgressOperationEventArgs> Completed;
        public event EventHandler<ProgressOperationEventArgs> Started;


        public List<Mp3File> Songs { get; private set; }

        private CancellationTokenSource _cancelToken;
        private IMP3Processor _mp3Processor;

        public FileSaver(CancellationTokenSource cancelToken, IMP3Processor mp3Processor)
        {
            _cancelToken = cancelToken;
            _mp3Processor = mp3Processor;
            Current = 0;
            Maximum = 0;
            Minimum = 0;
        }

        public void CancelAsync() { _cancelToken.Cancel(); }

        /// <summary>
        /// the folder will be scanned for Mp3
        /// </summary>
        /// <param name="folder">folder to scan</param>
        /// <returns>number of Mp3 file</returns>
        public int SaveCollection(List<Mp3File> songs)
        {
            Maximum = songs.Count;
            Songs = songs;
            Description = "Saving "+Maximum+" files";
            Current = 0;
            return Maximum;
        }

        public void Start()
        {
            Task.Factory.StartNew((Action)(()=>{

            if (Songs != null)
            {               
                if (Started != null)
                    foreach (Delegate d in Started.GetInvocationList())
                    {
                        d.DynamicInvoke(new object[] { null, new ProgressOperationEventArgs(0, Maximum, Description) });
                    }
                try
                {

                    ParallelOptions paralleSettings = new ParallelOptions();
                    paralleSettings.CancellationToken = _cancelToken.Token;
                    paralleSettings.MaxDegreeOfParallelism = ThreadHelper.CalculateTreads(Songs.Count(), ThreadingFactorEnum.Maximum);
                    //saving Mp3 in a parallel way
                    Parallel.ForEach<Mp3File>(Songs, paralleSettings, (song) =>
                    {

                        IMP3Processor mp3Processor = new IDSharpProcessor();
                        try
                        {
                            bool res = mp3Processor.SaveID3Tag(song);
                            if (res)
                            {
                                //to save memory, unload the image
                                song.Cover = null;
                                song.Dirty = false;
                                Current++;
                                if (ProgressChanged != null)
                                    foreach (Delegate d in ProgressChanged.GetInvocationList())
                                    {
                                        d.DynamicInvoke(new object[] { this, new ProgressOperationEventArgs(Current, Maximum, Description) });

                                    }
                            }
                        }
                        catch (OperationCanceledException ce)
                        {
                            //user interrupted the operation
                            Trace.WriteLine("[INFO] FileSaver: Operation stopped");
                        }
                        catch (Exception e)
                        {
                            Trace.WriteLine("[ERROR] FileSaver: Song not saved: " + e.Message);

                        }

                    });
                }
                catch (AggregateException ae)
                {
                    //do nothing
                }
                finally
                {

                    if (Completed != null)
                        foreach (Delegate d in Completed.GetInvocationList())
                        {
                            d.DynamicInvoke(new object[] { this, new ProgressOperationEventArgs(Current, Maximum, Description) });
                        }

                    Songs = null;
                }
            }
            }));
            
        }
    }
}
